// 编译
#pragma once
#include "../Comm/log.hpp"
#include "../Comm/util.hpp"
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/stat.h>

namespace ns_compiler
{
    using namespace ns_util;
    static const string Stand = "-std=c++14";
    
    class Compiler
    {
    public:
        static int Compile(const std::string &file_name)
        {
            // 创建子进程->程序替换:g++编译器
            pid_t id = fork();
            if (-1 == id)
            {
                LOG(ERROR, "【编译】 fork():%s", strerror(errno));
                return -1;
            }
            else if (0 == id)
            {
                // 子进程
                // g++ -o file_name.exe file_name.cpp -std=c++14 -w

                // 如果编译出错，将编译信息（waring && error）重定向到指定文件
                umask(0);
                int fd = open(PathUtil::CompileErr(file_name).c_str(), O_CREAT | O_WRONLY, 0644);
                if (-1 == fd)
                {
                    LOG(ERROR, "【编译】 open():%s", strerror(errno));
                    exit(-1);
                }
                int ret = dup2(fd, 2);
                if (-1 == fd)
                {
                    LOG(ERROR, "【编译】 dup2():%s", strerror(errno));
                    exit(-1);
                }

                // 程序替换不影响fd
                ret = execlp("g++", "g++", PathUtil::Src(file_name).c_str(),
                            "-D__TEMP__",
                             "-o", PathUtil::Exe(file_name).c_str(),
                             Stand.c_str(), nullptr);

                if (-1 == ret)
                {
                    //LOG(ERROR, "【编译】 execlp():%s", strerror(errno));
                    exit(-1);
                }

                exit(0);
            }
            else
            {
                // 父进程
                int status = 0;
                pid_t ret = waitpid(id, &status, 0);
                if (-1 == ret)
                {
                    LOG(ERROR, "【编译】 waitpid(%d) failed", id);
                    return -1;
                }

                if (0 == status)
                {
                    // 编译成功
                    LOG(INFO, "编译成功 %s", PathUtil::Src(file_name).c_str());
                    return 0;
                }
            }
            LOG(INFO, "编译失败 %s\n", PathUtil::Src(file_name).c_str());
            return -3;//代码本身存在错误【编译错误】
        }
    };
}